#Introduction This analysis was done by Mike Goldweber, Sept 2023.
Submitted to DrivenData.org on Oct 6, 2023. This document shows; the
step by step process of analyzing the emergency room data provided in
the Unsupervised Wisdom contest.
Data Exploration
This is actually the critical portion of the project, and most of the
effort was spent on this work in order to understand the scope of the
problem. The results of this exploration affected later portions of the
exploration. Please note, the narrative column won’t be looked at in the
data exploration. The goal is to use ChatGPT to analyze this data and
return helpful results. So, this part of the data is being handled
separately.
Let’s begin by looking at correlations between the columns.
Correlation Plot
library(corrplot)
#we need to use numerical values for the correlation. So, we'll make a subset of the data.
df_numsubset<- df_original[, c(4:6, 8:9, 13, 15:22)]
#visualization matrix of the data, looking for correlations
corrplot(cor(df_numsubset), type= "upper")

We see strong correlations between race and hispanic, product_1 and
product_2, as well as product_2 and product_3. Honestly, this doesn’t
seem to be very helpful. At least as this stage. Our focus is on the
injuries. There are some connections to age and some of the other
factors. Including alcohol. So, we’ll have to explore this.
Age
Let’s look at the age category. In particular, let’s see if there is
a particular age that is hit harder than another age. The block converts
it into a table, and the plot shows the frequency of injuries by
age.
library(ggplot2)
#frequency of injuries by age
data <- df_numsubset[, c('age', 'sex')]
df_agefreq <- as.data.frame(table(data$age))
colnames(df_agefreq)[1] <- "age"
colnames(df_agefreq)[2] <- "frequency"
#head(df_agefreq)
ggplot(df_agefreq) +
geom_count(mapping = aes(x=age, y=frequency)) +
labs(title = "Frequency of Injury By Age", x="Age", y="Count")

What is interesting about this plot, it shows that the injury
frequency is relatively high (over 3500) until age 88. I am wondering if
the fall off is due to some environmental movement, or is the population
over 88 shrinking? There is a bit of a plateau for ages 71-80, where
each group has over 4000 injuries, except for age 76 with 3993
injuries.
Sex (Gender)
Next, let’s look at the breakdown of sex (gender) in this
dataset.
#63% of the injuries are to women
genderlabels <- c("Male", "Female")
gender <- as.vector(df_original[ ,'sex'])
gentable <- as.data.frame(table(gender))
gentable$gender <- mapvalues(gentable$gender, c( "1", "2"), genderlabels)
pie(gentable$Freq, labels = genderlabels, main="Sex Breakdown")

percentoffemales <- (gentable[2, 'Freq']/nrow(df_original)*100)
out <- sprintf("Percentage of females in this dataset: %f)", percentoffemales) #percentage of females in this dataset
out
[1] "Percentage of females in this dataset: 63.115836)"
This plot visually shows the breakdown of sex in this dataset. We see
that at 63.1%, females represents the majority of cases
in this dataset. So, we’ll pay particular attention to the factors
affecting this part of the population.
Age and Gender
Next, let’s look at the split by age and gender.
library(ggplot2)
library(sqldf)
library(reshape2)
results <- sqldf('SELECT age, sex, count(sex) AS "frequency"
FROM dfmapping
GROUP BY age, sex')
# reshape the dataframe into a long format
results <- melt (results, id.vars = c ("sex", "age"))
# plot two lines for different genders
ggplot (results, aes (x = age, y = value, group = sex, color = sex)) +
geom_line () +
labs (x = "Age", y = "Injury Frequency", color = "Sex")

This chart shows a significant difference by gender across the ages
of the patients. First, this plot confirms the previous pie chart plot
by showing the female population suffers greater numbers of injuries
across the age spectrum. As we explore further, we’ll have to
consider the possibility of using different approaches for helping each
gender. Of note, this shows the data set only includes males and
females. The other categories are not represented in this dataset.
Data Exploration by Race and Sex
Next, let’s factor in the race of the patients to see if any
particular group is affected more than the others. After looking at the
upper level data by race, we’ll look at the hispanic breakdown at the
population.
Breakdown By Race
We’ll start off with a simple pie chart to see.
if (system.file(package = "waffle") == "") {
install.packages("waffle")
}
library(ggplot2)
library(waffle)
rcounts <- as.data.frame(table(df_mapped$race))
colnames(rcounts)[1]<-"race"
colnames(rcounts)[2]<-"frequency"
vec <- numeric()
vecS <- character()
for(i in rcounts$frequency)
{
x <- i/rowcount
x <- x*100
vec <- c(vec, x)
s <- ifelse((x > 7.0), sprintf("%.2f%%", x), "")#display only meaning values on the pie chart
vecS <- c(vecS, s)
}
rcounts <- cbind(rcounts, new_col = vec)
colnames(rcounts)[3]<-"percent"
rcounts <- cbind(rcounts, new_col = vecS)
colnames(rcounts)[4]<-"labels"
ggplot(rcounts, aes(x = "", y = percent, fill = race)) +
geom_bar(stat="identity", width=1) +
geom_text(aes(label = labels), position = position_stack(vjust = 0.5)) +
scale_fill_manual(values = c("#E59866", "#FCF3CF", "#AF601A", "#AED6F1", "#BD0026", "#27AE60", "#FAD7AD")) + ##E59866
coord_polar("y", start=0) +
labs(title = "Breakdown of the Patient Population by Race",
#subtitle = "test",
caption = "34.4% did not state their race, making a racial correlation difficult")

This chart is problematic, because of the high percentage of N.S.
(not stated). So it maybe difficult to accurately identify a racial
component to these injuries.
Hispanic
if (system.file(package = "waffle") == "") {
install.packages("waffle")
}
library(ggplot2)
library(waffle)
hcounts <- as.data.frame(table(df_mapped$hispanic))
colnames(hcounts)[1]<-"hispanic"
colnames(hcounts)[2]<-"frequency"
vec <- numeric()
vecS <- character()
for(i in hcounts$frequency)
{
x <- i/rowcount
x <- x*100
vec <- c(vec, x)
s <- sprintf("%.2f%%", x)
vecS <- c(vecS, s)
}
hcounts <- cbind(hcounts, new_col = vec)
colnames(hcounts)[3]<-"percent"
hcounts <- cbind(hcounts, new_col = vecS)
colnames(hcounts)[4]<-"labels"
ggplot(hcounts, aes(x = "", y = percent, fill = hispanic)) +
geom_bar(stat="identity", width=3) +
geom_text(aes(label = labels), position = position_stack(vjust = 0.5)) +
scale_fill_manual(values = c("#E59866","#27AE60", "#FCF3CF")) +
coord_polar("y", start=0) +
labs(title = "Breakdown of the Hispanic Population",
#subtitle = "test",
caption = "Only 3% of the patients identify as Hispanic")

So, the majority of patients are not hispanic, however, we can’t
conclude not being hispanic makes a person more likey to fall.
rhcounts <- as.data.frame(table(df_mapped$hispanic, df_mapped$race))
colnames(rhcounts)[1]<-"hispanic"
colnames(rhcounts)[2]<-"race"
colnames(rhcounts)[3]<-"frequency"
webr::PieDonut(rhcounts, aes(hispanic, race, count=frequency),
r0 = 0.3, #hides the center
r1 = 0.7,
#explode = 3,
#explodeDonut = TRUE,
pieLabelSize = 3,
donutLabelSize = 4,
title = "Hispanic and Racial Breakdown")
Warning: The `<scale>` argument of `guides()` cannot be `FALSE`. Use "none" instead as of ggplot2 3.3.4.

As with the Hispanic pie chart, and with only 3% of the injured set
being hispanic, I’m not convinced that hispanic=yes correlates to a
fall. Further, no one racial group stands out Certainly, part of the
Unk/Not Stated group is probably hispanic, but we don’t know for
certain. Further obfuscating this part of the hispanic set is the N.S
part of the race data, which represents 76% of the Unknown hispanic
group.
We’ll continue to look at race, but I don’t believe there is anything
to be gained from including the hispanic column in our model.
rm(rhcounts)
Warning: object 'rhcounts' not found
Diagnosis
Next is a look at the diagnosis column. We’ll start off by looking
for the most heavily diagnosed injuries.
#grouping the diagnosis column, looking for the most frequent injury
##frequency of each diagnosis
dcounts <-df_mapped[, c('diagnosis')]
df_diagnosisfreq <- as.data.frame(table(dcounts))
colnames(df_diagnosisfreq)[1] <- "diagnosis_code"
colnames(df_diagnosisfreq)[2] <- "frequency"
#sort the data in descending order
df_diagnosisfreqSorted <- df_diagnosisfreq[order(-df_diagnosisfreq$frequency),]
head(df_diagnosisfreqSorted)
#cleanup
rm(dcounts, df_diagnosisfreq)
From this sorting, we know that fractures, internal injuries,
contusions abj, and lacertations make up the majority of the 26 listed
injuries by a significant amount.

Seeing the majority (86%) of the dataset is diagnosed with these 4
injuries (fractures, internal injuries, contusions abj, and
lacertations), our focus will be on how age, race and location play a
part with these injuries.
#cleanup
rm(vec, vecS, vecColor, df_diagnosisfreqSorted)
Fire Involvement and Alcohol
Related to the injuries are the cases of burns and alcohol having an
effect on the falling injuries. Let’s take a look to see how the patient
population in this dataset has been affected by them.We know from the
diagnosis frequencies, that burn injuries
Fire Involvement
##frequency of the burn diagnosis
burncounts <- sqldf('SELECT diagnosis, count(diagnosis) AS "frequency"
FROM dfmapping
WHERE (diagnosis = "47 - BURN, NOT SPEC." or diagnosis = "49 - BURN, CHEMICAL" or diagnosis = "48 - BURN, SCALD" or diagnosis = "51 - BURNS, THERMAL")
GROUP BY diagnosis
ORDER BY frequency DESC')
head(burncounts)
##frequency of fire_involvement
fcounts <-df_mapped[, c('fire_involvement')]
df_firefreq <- as.data.frame(table(fcounts))
colnames(df_firefreq)[1] <- "fire_involvement"
colnames(df_firefreq)[2] <- "frequency"
#sort the data in descending order
df_FireIsFreqSorted <- df_firefreq[order(-df_firefreq$frequency),]
head(df_FireIsFreqSorted)
#cleanup
rm(burncounts, fcounts, df_firefreq, df_FireIsFreqSorted)
From these numbers, we see there is very few burn injuries. Eightyone
total, or 0.7% of the total dataset. For this project, we won’t explore
burn injuries or fire involvement further because this is such a small
part of the population.
Alcohol
Unlike the burns and fire involvement, there isn’t a set of injuries
that specifically connects with alcohol usage. So, if we see a large
number of patients that reported alcohol usage, it will be interesting
to see which diagnosis were tied to it.
##frequency of the burn diagnosis
alcoholcounts <- sqldf('SELECT alcohol, count(alcohol) AS "frequency"
FROM dfmapping
GROUP BY alcohol
ORDER BY frequency DESC')
head(alcoholcounts)
yestotal <- alcoholcounts[2,2]
percent <- yestotal/rowcount*100
print(sprintf("Percentage of cases where alcohol was related to the falling injury: %.2f%%.", percent))
[1] "Percentage of cases where alcohol was related to the falling injury: 2.25%."
#cleanup
rm(alcoholcounts, yestotal, percent)
The number of alcohol related cases is 2588, or 2.25% of the patients
in the dataset. For this project, we won’t explore alcohol further
because this represents a small part of the population.
Locations Where Patients Reported Getting Hurt
I want to take a quick look at where people are getting hurt. This
could impact how we look for correlations later on.
locationresults <- sqldf('SELECT location, count(location) AS "frequency"
FROM dfmapping
WHERE (diagnosis = "53 - CONTUSIONS, ABR." or diagnosis = "57 - FRACTURE" or diagnosis = "59 - LACERATION" or diagnosis = "62 - INTERNAL INJURY")
GROUP BY location')
pie(locationresults$frequency, labels = locationresults$location, main="Location Breakdown")

#percentoffemales <- (gentable[2, 'Freq']/rowcount*100)
#ut <- sprintf("Percentage of females in this dataset: %f)", percentoffemales) #percentage of females in this dataset
#out
This pie chart isn’t the prettiest, but it does clearly show that
Home is the primary location where injuries take place. This is followed
up by Public and Unknown. Unknown is a frustrating result for this
portion of the data, because it isn’t clear how to mitigate problems at
this location.
Diagnosis, Race, and Gender
Let’s look to see if there is any correlation between the injuries,
race, and gender, with the focus being on the top 4 injuries identified
above.

From this plot, we can see that women are severely diagnosed with “57
- Fractures” and “63 - Internal Injury”; however, women suffer from all
of these top diagnosis more than men. So special
attention has to be paid for addressing the factors affecting
women.
Diagnosis, Sex (Gender), and Location
So far, we’ve seen individual breakdowns of the data, but let’s start
mixing up the columns in the hopes of exposing a culprete to the
problem.
locationresults <- sqldf('SELECT location, diagnosis, sex, count(sex) AS "frequency"
FROM dfmapping
WHERE (diagnosis = "53 - CONTUSIONS, ABR." or diagnosis = "57 - FRACTURE" or diagnosis = "59 - LACERATION" or diagnosis = "62 - INTERNAL INJURY")
GROUP BY location, diagnosis, sex')
sum(locationresults$frequency) #results = 99868
[1] 99868
#<- df_firefreq[order(-df_firefreq$frequency),]
sorted <- locationresults[order(-locationresults$frequency),]
head(sorted)
rm(locationresults, sorted)
This result is interesting because we see that fractures and internal
injuries affect women by a significant amount at
home.
Location, Diagnosis, Body Part
Now that we’ve identified females are being disproportional hurt at
home, which body_part is affected the most?
I’m focused on the women, however, let’s continue to look at men in
the query.
locationresults <- sqldf('SELECT location, diagnosis, body_part, sex, count(sex) AS "frequency"
FROM dfmapping
WHERE (diagnosis = "53 - CONTUSIONS, ABR." or diagnosis = "57 - FRACTURE" or diagnosis = "59 - LACERATION" or diagnosis = "62 - INTERNAL INJURY")
GROUP BY location, diagnosis, body_part, sex')
sum(locationresults$frequency) #results = 99868
[1] 99868
#<- df_firefreq[order(-df_firefreq$frequency),]
sorted <- locationresults[order(-locationresults$frequency),]
head(sorted)
NA
These results are helpful. Previously we saw fractures at the most
serious problem. However, when we factor in the body_part we see the
internal injuries to the head at home and in the public location is the
most serious problem
rm(locationresults, sorted)
Let’s look at this same data with just the women.
locationresults <- sqldf('SELECT location, diagnosis, body_part, sex, count(sex) AS "frequency"
FROM dfmapping
WHERE (diagnosis = "53 - CONTUSIONS, ABR." or diagnosis = "57 - FRACTURE" or diagnosis = "59 - LACERATION" or diagnosis = "62 - INTERNAL INJURY") AND
(sex = "FEMALE")
GROUP BY location, diagnosis, body_part, sex')
sum(locationresults$frequency) #results = 99868
[1] 63248
#<- df_firefreq[order(-df_firefreq$frequency),]
sorted <- locationresults[order(-locationresults$frequency),]
head(sorted)
NA
From this table, we see that when the diagnosis is an internal
injury, the head is the body part injuried the most. Home is the most
likely place for the injuries, followed by the public or unknown
locations. Next most frequent injury is the upper or lower trunk
experiencing fractures.
Let do a similar query for the males to see how they are
affected.
locationresults <- sqldf('SELECT location, diagnosis, body_part, sex, count(sex) AS "frequency"
FROM dfmapping
WHERE (diagnosis = "53 - CONTUSIONS, ABR." or diagnosis = "57 - FRACTURE" or diagnosis = "59 - LACERATION" or diagnosis = "62 - INTERNAL INJURY") AND
(sex = "MALE")
GROUP BY location, diagnosis, body_part, sex')
sum(locationresults$frequency) #results = 99868
[1] 36620
#<- df_firefreq[order(-df_firefreq$frequency),]
sorted <- locationresults[order(-locationresults$frequency),]
head(sorted)
NA
The results for men are very similar in that internal injuries to the
head are hit the male population with the greatest frequency. Also, like
the females, we see that males experience the fractures to the lower and
upper trunk most frequently (after the head injuries), and the major of
these injuries are at home.
Connections to Products?
Next, let’s see if there is a tie to the products.
locationresults <- sqldf('SELECT location, diagnosis, body_part, product_1, sex, count(sex) AS "frequency"
FROM dfmapping
WHERE (diagnosis = "53 - CONTUSIONS, ABR." or diagnosis = "57 - FRACTURE" or diagnosis = "59 - LACERATION" or diagnosis = "62 - INTERNAL INJURY")
GROUP BY location, diagnosis, body_part, product_1, sex')
#sum(locationresults$frequency) #results = 99868
#<- df_firefreq[order(-df_firefreq$frequency),]
sorted <- locationresults[order(-locationresults$frequency),]
head(sorted)
NA
This query shows the majority of products are tied to floors or
flooring materials. Does this mean the patient just fell on the floor
leading to the internal injuries and fractures? Also of note home,
internal injury, and heads are the most likely to be the combination for
our patients. Let’s look at the same data with just the floors.
locationresults <- sqldf('SELECT location, diagnosis, body_part, product_1, count(product_1) AS "frequency"
FROM df_mapped
WHERE (diagnosis = "53 - CONTUSIONS, ABR." or diagnosis = "57 - FRACTURE" or diagnosis = "59 - LACERATION" or diagnosis = "62 - INTERNAL INJURY")
AND (product_1 = "1807 - FLOORS OR FLOORING MATERIALS")
GROUP BY location, diagnosis, body_part, product_1')
sorted <- locationresults[order(-locationresults$frequency),]
head(sorted)
sum <- sum(locationresults$frequency)
percent <- sum/rowcount * 100
print( sprintf("The total frequency of the floor/ flooring materials injuries is %i, or %.2f%%.", sum, percent ))
[1] "The total frequency of the floor/ flooring materials injuries is 29348, or 25.49%."
As we combine the various data columns to our data exploration, we
are seeing distinct groupings of the factors that make up this
dataset.
Tieing Together the Data Exploration.
As previously observed, females at home, suffer internal injuries to
their heads when landing on the floors. Let’s look at the revised
dataset when we look at the most frequently sustain injuries.
if (system.file(package = "circlepacketR") == "") {
install.packages("circlepacketR")
}
Installing package into ‘C:/Users/mike/AppData/Local/R/win-library/4.3’
(as ‘lib’ is unspecified)
Warning in install.packages :
package ‘circlepacketR’ is not available for this version of R
A version of this package for your version of R might be available elsewhere,
see the ideas at
https://cran.r-project.org/doc/manuals/r-patched/R-admin.html#Installing-packages
library(sqldf)
#
locationresults <- sqldf('select sex, location, diagnosis, body_part, frequency
from(
SELECT sex, location, diagnosis, body_part, count(*) AS "frequency"
FROM df_mapped
WHERE (diagnosis = "53 - CONTUSIONS, ABR." or diagnosis = "57 - FRACTURE" or diagnosis = "59 - LACERATION" or diagnosis = "62 - INTERNAL INJURY")
GROUP BY sex, location, diagnosis, body_part
ORDER BY sex, location, diagnosis, body_part
) as t
WHERE frequency > 500
ORDER BY frequency DESC
')
Body Part 2, Products 2, and Product 3
I’m reluctant to delve too deeply into these columns. First, these 3
columns are mostly blank, so where there is data in these columns, it
seems to be a secondary result of the body_part and product_1. In other
words, if we come up with a way to prevent injury to body_part with
product_1, then we can prevent problems with body_part_2 and product_2
and product_3.
LS0tDQp0aXRsZTogIkVtZXJnZW5jeSBSb29tIEZhbGxpbmcgSW5qdXJ5IEFuYWx5c2lzIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KI0ludHJvZHVjdGlvbg0KVGhpcyBhbmFseXNpcyB3YXMgZG9uZSBieSBNaWtlIEdvbGR3ZWJlciwgU2VwdCAyMDIzLiBTdWJtaXR0ZWQgdG8gRHJpdmVuRGF0YS5vcmcgb24gT2N0IDYsIDIwMjMuIFRoaXMgZG9jdW1lbnQgc2hvd3M7DQp0aGUgc3RlcCBieSBzdGVwIHByb2Nlc3Mgb2YgYW5hbHl6aW5nIHRoZSBlbWVyZ2VuY3kgcm9vbSBkYXRhIHByb3ZpZGVkIGluIHRoZSBVbnN1cGVydmlzZWQgV2lzZG9tIGNvbnRlc3QuDQoNClRoZSBmdWxsIHNldCBvZiBwcm9qZWN0IGZpbGVzIGNhbiBiZSBmb3VuZCBhdDogaHR0cHM6Ly9naXRodWIuY29tL2hhbGNpYmVyL01hY2hpbmUtTGVhcm5pbmcvdHJlZS9tYXN0ZXIvVW5zdXBlcnZpc2VkV2lzZG9tLg0KDQojIERhdGEgSW5nZXN0aW9uDQpUaGUgZGF0YSB1c2VkIGluIHRoaXMgcHJvamVjdCBpcyB0aGUgUHJpbWFyeSBkYXRhIHNldC4gVGhpcyBjb250YWlucyAxMTUsMTI4IHJvd3Mgb2YgZGF0YS4gVGhlIGRhdGEgaXMgcHVsbGVkIGludG8gdHdvIGRhdGFmcmFtZXMuIE9uZSBjYWxsZWQgZGZfb3JpZ2luYWwsIGFuZCB0aGUgb3RoZXIgaXMgY2FsbGVkIGRmX21hcHBlZC4gVGhlIGRmX21hcHBlZCBzZXQgaXMgbW9kaWZpZWQgYnkgdGhlIGV4YW1wbGUgY29kZSBzbyB0aGF0IGl0IHByb2R1Y2VzIGh1bWFuIHJlYWRhYmxlIGRhdGEuIHRoZSBkZl9vcmlnaW5hbCBzZXQgd2lsbCBiZSBtb2RpZmllZCBieSB0aGUgZmVhdHVyZSBlbmdpbmVlciB0byBiZSB1c2FibGUgYnkgdGhlIG1vZGVsaW5nIGRvbmUgYmVsb3cuDQoNCg0KDQpgYGB7cn0NCiNZb3UnbGwgd2FudCB0byBhZGp1c3QgeW91ciBmaWxlIHBhdGggZm9yIHlvdXIgZW52aXJvbm1lbnQNCmZpbGVwYXRoIDwtICJjOlxcX3dvcmtpbmdcXE1hY2hpbmUtTGVhcm5pbmdcXFVuc3VwZXJ2aXNlZFdpc2RvbVxcRGF0YVxccHJpbWFyeV9kYXRhLmNzdiINCg0KZGZfb3JpZ2luYWwgPC0gcmVhZC5jc3YoZmlsZXBhdGgpDQoNCiN3ZSdsbCB1c2UgdGhpcyB2YXJpYWJsZSBmcmVxdWVudGx5DQpyb3djb3VudCA8LSBucm93KGRmX21hcHBlZCkNCmBgYA0KDQojIyBTZXR0aW5nIHVwIHRoZSBjYXRlZ29yaWNhbCBtYXBwaW5nIGRhdGFmcmFtZQ0KVGhlIGNvZGUgZm9yIHRoZSBuZXh0IHR3byBibG9ja3Mgd2FzIHRha2UgZGlyZWN0bHkgZnJvbSB0aGUgQ29tbXVuaXR5IENvZGUgc2VjdGlvbiBvZiB0aGUgY29udGVzdCB3ZWJzaXRlLCBmb3VuZCBhdDogaHR0cHM6Ly93d3cuZHJpdmVuZGF0YS5vcmcvY29tcGV0aXRpb25zLzIxNy9jZGMtZmFsbC1uYXJyYXRpdmVzL2NvbW11bml0eS1jb2RlLy5UaGUgcHVycG9zZSBvZiB0aGlzIGJsb2NrIGlzIHRvIHRha2UgdGhlIEpTT04gY29kaW5nIGluZm9ybWF0aW9uIGFuZCBtYXRjaCBpdCB0byB0aGUgbnVtZXJpYyB2YWx1ZXMgZm91bmQgaW4gcHJpbWFyeV9kYXRhLmNzdi4gSSd2ZSBmb3VuZCB0aGlzIHZlcnNpb24gb2YgdGhlIGRhdGFzZXQgdG8gYmUgaGVscGZ1bCBpbiB1bmRlcnN0YW5kaW5nIHRoZSBkYXRhLiBGb3IgZXhhbXBsZSwgIjU3IC0gRlJBQ1RVUkUiIGlzIG1vcmUgbWVhbmluZ2Z1bCB0aGFuIHRoZSBvcmlnaW5hbCAiNTciLiBNeSBpbnRlbnRpb24gaXMgdG8gdXNlIHRoZSBkZl9tYXBwZWQgZGF0YWZyYW1lIHByaW1hcmlseSB3aXRoIHRoZSBkYXRhIGV4cGxvcmF0aW9uIGFuZCB0aGUuIGRmX29yaWdpbmFsLCBjcmVhdGVkIGluIHRoZSBjb2RlIGJsb2NrIGFib3ZlIHdpbGwgYmUgdXNlZCBmb3IgdGhlIG1vZGVsaW5nIHdvcmsgYWZ0ZXIgbW9kaWZpY2F0aW9uIGluIHRoZSBGZWF0dXJlIEVuZ2luZWVyIHNlY3Rpb24gYmVsb3cuDQoNCmBgYHtyfQ0KbGlicmFyeShqc29ubGl0ZSkNCg0KbWFwcGluZ2ZpbGUgPC0gJ2M6XFxfd29ya2luZ1xcTWFjaGluZS1MZWFybmluZ1xcVW5zdXBlcnZpc2VkV2lzZG9tXFxEYXRhXFx2YXJpYWJsZV9tYXBwaW5nLmpzb24nDQptYXBwaW5nIDwtIGZyb21KU09OKG1hcHBpbmdmaWxlKQ0KbmFtZXMobWFwcGluZykNCg0KIyBDb252ZXJ0IHRvIGRhdGEgZnJhbWVzIHNvIHdlIGNhbiB1c2UgaW4gam9pbnMNCm1hcHBpbmdfdGFibGVzIDwtIGxpc3QoKQ0KZm9yIChjb2wgaW4gbmFtZXMobWFwcGluZykpIHsNCiAgICBtYXBwaW5nX3RhYmxlc1tbY29sXV0gPC0gZGF0YS5mcmFtZSgNCiAgICAgICAgaW5kPWFzLmludGVnZXIobmFtZXMobWFwcGluZ1tbY29sXV0pKSwgICMgY2hhbmdlIHRvIGludGVnZXIgdHlwZXMNCiAgICAgICAgdmFsdWVzPXVubGlzdChtYXBwaW5nW1tjb2xdXSkNCiAgICApDQp9DQpgYGANCg0KTm93IHRoYXQgdGhlIEpTT04gaW5mb3JtYXRpb24gaGFzIGJlZW4gaW5nZXN0ZWQsIHdlJ2xsIG1hcCB0aGUgY2F0ZWdvcmllcyBvbiB0byB0aGUgZGF0YWZyYW1lLCB3aGljaCB3ZSB3aWxsIGNhbGwgKipkZl9tYXBwZWQqKi4NCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCg0KIyBMb2FkIHByaW1hcnkgZGF0YQ0KZGZfbWFwcGVkIDwtIGRmX3ByaW1hcnkNCg0KIyBKb2luIGFuZCByZXBsYWNlIGVuY29kZWQgY29sdW1uDQpmb3IgKGNvbCBpbiBuYW1lcyhtYXBwaW5nKSkgew0KICAgIGRmX21hcHBlZCA8LSBkZl9tYXBwZWQgJT4lDQogICAgICAgIGxlZnRfam9pbihtYXBwaW5nX3RhYmxlc1tbY29sXV0sIGJ5PXNldE5hbWVzKCJpbmQiLCBjb2wpKSAlPiUNCiAgICAgICAgbXV0YXRlKCEhY29sIDo9IHZhbHVlcykgJT4lDQogICAgICAgIHNlbGVjdCgtdmFsdWVzKQ0KfQ0KDQoNCmBgYA0KDQoNCg0KDQoNCiMgRGF0YSBDbGVhbiBVcC8gUHJlbGltaW5hcnkgRmVhdHVyZSBFbmdpbmVlcg0KTGV0J3MgbG9vayBhdCB0aGUgZGF0YXNldCB0byBnZXQgYW4gaW5pdGlhbCBmZWVsIGZvciB0aGUgZGF0YSBxdWFsaXR5IGJ5IHJ1bm5pbmcgYSBzdW1tYXJ5DQoNCmBgYHtyfQ0Kc3VtbWFyeShkZl9vcmlnaW5hbCkNCmBgYA0KVXN1YWxseSBhIGNvbmNlcm4gaXMgbWlzc2luZyBkYXRhIHNjYXR0ZXJlZCByYW5kb21seSB0aG91Z2h0b3V0IHRoZSBzZXQuIEluIHRoaXMgY2FzZSwgdGhlIHN1bW1hcnkgc2hvd3MgdGhlIGRhdGEgaXMgaW4gZ29vZCBzaGFwZS4gVGhhdCBpcyB0aGVyZSBpc24ndCBtdWNoIGluIHRoZSB3YXkgb2YgbWlzc2luZyBkYXRhLiBUaGUgb25seSBOQSdzIHdlIHNlZSBhcmUgaW4gdGhlIGRpYWdub3Npc18yIGFuZCBib2R5X3BhcnRfMiBjb2x1bW5zLiBUaGlzIGlzbid0IGEgc3VwcmlzZSwgYmVjYXVzZSB0aGUgRVIgcGF0aWVudHMgZGlkbid0IG5lY2Vzc2FyaWx5IHN1ZmZlciBzZWNvbmRhcnkgaW5qdXJpZXMuIFRoZXJlIGlzIGEgY29ycmVsYXRpb24gYmV0d2VlbiB0aGVzZSB0d28gY29sdW1ucywgZ2l2ZW4gdGhlIGlkZW50aWNhbCBudW1iZXIgb2YgTkFzIGF0IDcxLDk4My4gVGhlc2UgY29sdW1ucyB3aWxsIGhhdmUgdG8gYmUgZXhwbG9yZWQgZnVydGhlciB0byBkZXRlcm1pbmUgaWYgaXQgc2hvdWxkIGJlIHVzZWQgaW4gb3VyIG1vZGVsaW5nLg0KDQpIb3dldmVyLCBnbGFuY2luZyBhdCB0aGUgZGF0YSBzZXRzIGRpcmVjdGx5IHNob3dzIGdhcHMgaW4gc29tZSBvZiB0aGUgb3RoZXIgY29sdW1ucy4gRm9yIGV4YW1wbGUgYm9keV9wYXJ0XzIsIG90aGVyX2RpYWdub3NpcyBhbmQgb3RoZXJfZGlhZ25vc2lzXzIgY29udGFpbiBtYW55IGdhcHMuDQoNCmBgYHtyfQ0KI3Njcm9sbCB0byB0aGUgcmlnaHQgdG8gc2VlIHRoZSBlbXB0eSBjb2x1bW5zIChleGFtcGxlIGJvZHlfcGFydF8yLCBvdGhlcl9kaWFnbm9zaXMgYW5kIG90aGVyX2Rpc2Fnbm9zaXNfMikuDQpoZWFkKGRmX21hcHBlZCkNCmBgYA0KDQoNCiMgRGF0YSBFeHBsb3JhdGlvbg0KVGhpcyBpcyBhY3R1YWxseSB0aGUgY3JpdGljYWwgcG9ydGlvbiBvZiB0aGUgcHJvamVjdCwgYW5kIG1vc3Qgb2YgdGhlIGVmZm9ydCB3YXMgc3BlbnQgb24gdGhpcyB3b3JrIGluIG9yZGVyIHRvIHVuZGVyc3RhbmQgdGhlIHNjb3BlIG9mIHRoZSBwcm9ibGVtLiBUaGUgcmVzdWx0cyBvZiB0aGlzIGV4cGxvcmF0aW9uIGFmZmVjdGVkIGxhdGVyIHBvcnRpb25zIG9mIHRoZSBleHBsb3JhdGlvbi4gUGxlYXNlIG5vdGUsIHRoZSBuYXJyYXRpdmUgY29sdW1uIHdvbid0IGJlIGxvb2tlZCBhdCBpbiB0aGUgZGF0YSBleHBsb3JhdGlvbi4gVGhlIGdvYWwgaXMgdG8gdXNlIENoYXRHUFQgdG8gYW5hbHl6ZSAgdGhpcyBkYXRhIGFuZCByZXR1cm4gaGVscGZ1bCByZXN1bHRzLiBTbywgdGhpcyBwYXJ0IG9mIHRoZSBkYXRhIGlzIGJlaW5nIGhhbmRsZWQgc2VwYXJhdGVseS4NCg0KTGV0J3MgYmVnaW4gYnkgbG9va2luZyBhdCBjb3JyZWxhdGlvbnMgYmV0d2VlbiB0aGUgY29sdW1ucy4NCg0KIyMgQ29ycmVsYXRpb24gUGxvdA0KDQpgYGB7cn0NCmxpYnJhcnkoY29ycnBsb3QpDQoNCiN3ZSBuZWVkIHRvIHVzZSBudW1lcmljYWwgdmFsdWVzIGZvciB0aGUgY29ycmVsYXRpb24uIFNvLCB3ZSdsbCBtYWtlIGEgc3Vic2V0IG9mIHRoZSBkYXRhLg0KZGZfbnVtc3Vic2V0PC0gZGZfb3JpZ2luYWxbLCBjKDQ6NiwgODo5LCAxMywgMTU6MjIpXQ0KDQojdmlzdWFsaXphdGlvbiBtYXRyaXggb2YgdGhlIGRhdGEsIGxvb2tpbmcgZm9yIGNvcnJlbGF0aW9ucw0KY29ycnBsb3QoY29yKGRmX251bXN1YnNldCksIHR5cGU9ICJ1cHBlciIpDQpgYGANCldlIHNlZSBzdHJvbmcgY29ycmVsYXRpb25zIGJldHdlZW4gcmFjZSBhbmQgaGlzcGFuaWMsIHByb2R1Y3RfMSBhbmQgcHJvZHVjdF8yLCBhcyB3ZWxsIGFzIHByb2R1Y3RfMiBhbmQgcHJvZHVjdF8zLiBIb25lc3RseSwgdGhpcyBkb2Vzbid0IHNlZW0gdG8gYmUgdmVyeSBoZWxwZnVsLiBBdCBsZWFzdCBhcyB0aGlzIHN0YWdlLiBPdXIgZm9jdXMgaXMgb24gdGhlIGluanVyaWVzLiBUaGVyZSBhcmUgc29tZSBjb25uZWN0aW9ucyB0byBhZ2UgYW5kIHNvbWUgb2YgdGhlIG90aGVyIGZhY3RvcnMuIEluY2x1ZGluZyBhbGNvaG9sLiBTbywgd2UnbGwgaGF2ZSB0byBleHBsb3JlIHRoaXMuDQoNCiMjIEFnZQ0KTGV0J3MgbG9vayBhdCB0aGUgYWdlIGNhdGVnb3J5LiBJbiBwYXJ0aWN1bGFyLCBsZXQncyBzZWUgaWYgdGhlcmUgaXMgYSBwYXJ0aWN1bGFyIGFnZSB0aGF0IGlzIGhpdCBoYXJkZXIgdGhhbiBhbm90aGVyIGFnZS4gVGhlIGJsb2NrIGNvbnZlcnRzIGl0IGludG8gYSB0YWJsZSwgYW5kIHRoZSBwbG90IHNob3dzIHRoZSBmcmVxdWVuY3kgb2YgaW5qdXJpZXMgYnkgYWdlLg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQoNCg0KI2ZyZXF1ZW5jeSBvZiBpbmp1cmllcyBieSBhZ2UNCmRhdGEgPC0gZGZfbnVtc3Vic2V0WywgYygnYWdlJywgJ3NleCcpXQ0KZGZfYWdlZnJlcSA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKGRhdGEkYWdlKSkNCmNvbG5hbWVzKGRmX2FnZWZyZXEpWzFdIDwtICJhZ2UiIA0KY29sbmFtZXMoZGZfYWdlZnJlcSlbMl0gPC0gImZyZXF1ZW5jeSIgDQojaGVhZChkZl9hZ2VmcmVxKQ0KZ2dwbG90KGRmX2FnZWZyZXEpICsgDQogICAgZ2VvbV9jb3VudChtYXBwaW5nID0gYWVzKHg9YWdlLCB5PWZyZXF1ZW5jeSkpICsgDQogICAgbGFicyh0aXRsZSA9ICJGcmVxdWVuY3kgb2YgSW5qdXJ5IEJ5IEFnZSIsIHg9IkFnZSIsIHk9IkNvdW50IikNCmBgYA0KV2hhdCBpcyBpbnRlcmVzdGluZyBhYm91dCB0aGlzIHBsb3QsIGl0IHNob3dzIHRoYXQgdGhlIGluanVyeSBmcmVxdWVuY3kgaXMgcmVsYXRpdmVseSBoaWdoIChvdmVyIDM1MDApIHVudGlsIGFnZSA4OC4gSSBhbSB3b25kZXJpbmcgaWYgdGhlIGZhbGwgb2ZmIGlzIGR1ZSB0byBzb21lIGVudmlyb25tZW50YWwgbW92ZW1lbnQsIG9yIGlzIHRoZSBwb3B1bGF0aW9uIG92ZXIgODggc2hyaW5raW5nPyBUaGVyZSBpcyBhIGJpdCBvZiBhIHBsYXRlYXUgZm9yIGFnZXMgNzEtODAsIHdoZXJlIGVhY2ggZ3JvdXAgaGFzIG92ZXIgNDAwMCBpbmp1cmllcywgZXhjZXB0IGZvciBhZ2UgNzYgd2l0aCAzOTkzIGluanVyaWVzLiANCg0KIyMgU2V4IChHZW5kZXIpDQpOZXh0LCBsZXQncyBsb29rIGF0IHRoZSBicmVha2Rvd24gb2Ygc2V4IChnZW5kZXIpIGluIHRoaXMgZGF0YXNldC4NCg0KYGBge3J9DQojNjMlIG9mIHRoZSBpbmp1cmllcyBhcmUgdG8gd29tZW4NCg0KZ2VuZGVybGFiZWxzIDwtIGMoIk1hbGUiLCAiRmVtYWxlIikNCmdlbmRlciA8LSBhcy52ZWN0b3IoZGZfb3JpZ2luYWxbICwnc2V4J10pDQpnZW50YWJsZSA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKGdlbmRlcikpDQoNCmdlbnRhYmxlJGdlbmRlciA8LSBtYXB2YWx1ZXMoZ2VudGFibGUkZ2VuZGVyLCBjKCAiMSIsICIyIiksIGdlbmRlcmxhYmVscykNCg0KcGllKGdlbnRhYmxlJEZyZXEsIGxhYmVscyA9IGdlbmRlcmxhYmVscywgbWFpbj0iU2V4IEJyZWFrZG93biIpDQoNCnBlcmNlbnRvZmZlbWFsZXMgPC0gKGdlbnRhYmxlWzIsICdGcmVxJ10vcm93Y291bnQqMTAwKQ0Kb3V0IDwtIHNwcmludGYoIlBlcmNlbnRhZ2Ugb2YgZmVtYWxlcyBpbiB0aGlzIGRhdGFzZXQ6ICVmKSIsIHBlcmNlbnRvZmZlbWFsZXMpICNwZXJjZW50YWdlIG9mIGZlbWFsZXMgaW4gdGhpcyBkYXRhc2V0DQpvdXQNCg0KYGBgDQpUaGlzIHBsb3QgdmlzdWFsbHkgc2hvd3MgdGhlIGJyZWFrZG93biBvZiBzZXggaW4gdGhpcyBkYXRhc2V0LiBXZSBzZWUgdGhhdCBhdCAqKjYzLjElKiosIGZlbWFsZXMgcmVwcmVzZW50cyB0aGUgbWFqb3JpdHkgb2YgY2FzZXMgaW4gdGhpcyBkYXRhc2V0LiBTbywgd2UnbGwgcGF5IHBhcnRpY3VsYXIgYXR0ZW50aW9uIHRvIHRoZSBmYWN0b3JzIGFmZmVjdGluZyB0aGlzIHBhcnQgb2YgdGhlIHBvcHVsYXRpb24uDQoNCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQojY2xlYW51cA0Kcm0oZ2VuZGVyLCBnZW50YWJsZSwgZ2VuZGVybGFibGVzLCBvdXQpDQpgYGANCg0KDQoNCg0KDQojIyMgQWdlIGFuZCBHZW5kZXINCk5leHQsIGxldCdzIGxvb2sgYXQgdGhlIHNwbGl0IGJ5IGFnZSBhbmQgZ2VuZGVyLg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoc3FsZGYpDQpsaWJyYXJ5KHJlc2hhcGUyKQ0KDQpyZXN1bHRzIDwtIHNxbGRmKCdTRUxFQ1QgYWdlLCBzZXgsIGNvdW50KHNleCkgQVMgImZyZXF1ZW5jeSINCiAgICAgICAgICAgICAgICAgICAgICAgIEZST00gZGZfbWFwcGVkDQogICAgICAgICAgICAgICAgICAgICAgICBHUk9VUCBCWSBhZ2UsIHNleCcpDQoNCiMgcmVzaGFwZSB0aGUgZGF0YWZyYW1lIGludG8gYSBsb25nIGZvcm1hdA0KcmVzdWx0cyA8LSBtZWx0IChyZXN1bHRzLCBpZC52YXJzID0gYyAoInNleCIsICJhZ2UiKSkNCg0KIyBwbG90IHR3byBsaW5lcyBmb3IgZGlmZmVyZW50IGdlbmRlcnMNCmdncGxvdCAocmVzdWx0cywgYWVzICh4ID0gYWdlLCB5ID0gdmFsdWUsIGdyb3VwID0gc2V4LCBjb2xvciA9IHNleCkpICsNCiAgZ2VvbV9saW5lICgpICsNCiAgbGFicyAoeCA9ICJBZ2UiLCB5ID0gIkluanVyeSBGcmVxdWVuY3kiLCBjb2xvciA9ICJTZXgiKQ0KYGBgDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfSAgDQpybShyZXN1bHRzKQ0KYGBgDQoNCg0KVGhpcyBjaGFydCBzaG93cyBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgYnkgZ2VuZGVyIGFjcm9zcyB0aGUgYWdlcyBvZiB0aGUgcGF0aWVudHMuIEZpcnN0LCB0aGlzIHBsb3QgY29uZmlybXMgdGhlIHByZXZpb3VzIHBpZSBjaGFydCBwbG90IGJ5IHNob3dpbmcgdGhlIGZlbWFsZSBwb3B1bGF0aW9uIHN1ZmZlcnMgZ3JlYXRlciBudW1iZXJzIG9mIGluanVyaWVzICphY3Jvc3MgdGhlIGFnZSBzcGVjdHJ1bSouIEFzIHdlIGV4cGxvcmUgZnVydGhlciwgd2UnbGwgaGF2ZSB0byBjb25zaWRlciB0aGUgcG9zc2liaWxpdHkgb2YgdXNpbmcgZGlmZmVyZW50IGFwcHJvYWNoZXMgZm9yIGhlbHBpbmcgZWFjaCBnZW5kZXIuIE9mIG5vdGUsIHRoaXMgc2hvd3MgdGhlIGRhdGEgc2V0IG9ubHkgaW5jbHVkZXMgbWFsZXMgYW5kIGZlbWFsZXMuIFRoZSBvdGhlciBjYXRlZ29yaWVzIGFyZSBub3QgcmVwcmVzZW50ZWQgaW4gdGhpcyBkYXRhc2V0Lg0KDQoNCiMjIERhdGEgRXhwbG9yYXRpb24gYnkgUmFjZSBhbmQgU2V4DQpOZXh0LCBsZXQncyBmYWN0b3IgaW4gdGhlIHJhY2Ugb2YgdGhlIHBhdGllbnRzIHRvIHNlZSBpZiBhbnkgcGFydGljdWxhciBncm91cCBpcyBhZmZlY3RlZCBtb3JlIHRoYW4gdGhlIG90aGVycy4gQWZ0ZXIgbG9va2luZyBhdCB0aGUgdXBwZXIgbGV2ZWwgZGF0YSBieSByYWNlLCB3ZSdsbCBsb29rIGF0IHRoZSBoaXNwYW5pYyBicmVha2Rvd24gYXQgdGhlIHBvcHVsYXRpb24uDQoNCg0KIyMjIEJyZWFrZG93biBCeSBSYWNlDQpXZSdsbCBzdGFydCBvZmYgd2l0aCBhIHNpbXBsZSBwaWUgY2hhcnQgdG8gc2VlLg0KDQoNCmBgYHtyfQ0KDQppZiAoc3lzdGVtLmZpbGUocGFja2FnZSA9ICJ3YWZmbGUiKSA9PSAiIikgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJ3YWZmbGUiKQ0KfQ0KDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHdhZmZsZSkNCg0KcmNvdW50cyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKGRmX21hcHBlZCRyYWNlKSkNCmNvbG5hbWVzKHJjb3VudHMpWzFdPC0icmFjZSINCmNvbG5hbWVzKHJjb3VudHMpWzJdPC0iZnJlcXVlbmN5Ig0KDQp2ZWMgPC0gbnVtZXJpYygpDQp2ZWNTIDwtIGNoYXJhY3RlcigpDQoNCmZvcihpIGluIHJjb3VudHMkZnJlcXVlbmN5KQ0Kew0KICAgIHggPC0gaS9yb3djb3VudA0KICAgIHggPC0geCoxMDANCiAgICB2ZWMgPC0gYyh2ZWMsIHgpDQogICAgDQogICAgcyA8LSBpZmVsc2UoKHggPiA3LjApLCBzcHJpbnRmKCIlLjJmJSUiLCB4KSwgIiIpI2Rpc3BsYXkgb25seSBtZWFuaW5nIHZhbHVlcyBvbiB0aGUgcGllIGNoYXJ0DQogICAgdmVjUyA8LSBjKHZlY1MsIHMpDQp9DQoNCnJjb3VudHMgPC0gY2JpbmQocmNvdW50cywgbmV3X2NvbCA9IHZlYykNCmNvbG5hbWVzKHJjb3VudHMpWzNdPC0icGVyY2VudCINCg0KcmNvdW50cyA8LSBjYmluZChyY291bnRzLCBuZXdfY29sID0gdmVjUykNCmNvbG5hbWVzKHJjb3VudHMpWzRdPC0ibGFiZWxzIg0KDQpnZ3Bsb3QocmNvdW50cywgYWVzKHggPSAiIiwgeSA9IHBlcmNlbnQsIGZpbGwgPSByYWNlKSkgKw0KICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHdpZHRoPTEpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGxhYmVscyksIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNFNTk4NjYiLCAiI0ZDRjNDRiIsICIjQUY2MDFBIiwgIiNBRUQ2RjEiLCAiI0JEMDAyNiIsICIjMjdBRTYwIiwgIiNGQUQ3QUQiKSkgKyAjI0U1OTg2Ng0KICBjb29yZF9wb2xhcigieSIsIHN0YXJ0PTApICsgDQogIGxhYnModGl0bGUgPSAiQnJlYWtkb3duIG9mIHRoZSBQYXRpZW50IFBvcHVsYXRpb24gYnkgUmFjZSIsDQogICAgICAgICAgI3N1YnRpdGxlID0gInRlc3QiLA0KICAgICAgICAgIGNhcHRpb24gPSAiMzQuNCUgZGlkIG5vdCBzdGF0ZSB0aGVpciByYWNlLCBtYWtpbmcgYSByYWNpYWwgY29ycmVsYXRpb24gZGlmZmljdWx0IikNCmBgYCAgICANCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9ICANCnJtKHZlYywgdmVjUywgeCwgcywgcmNvdW50cykNCmBgYA0KVGhpcyBjaGFydCBpcyBwcm9ibGVtYXRpYywgYmVjYXVzZSBvZiB0aGUgaGlnaCBwZXJjZW50YWdlIG9mIE4uUy4gKG5vdCBzdGF0ZWQpLiBTbyBpdCBtYXliZSBkaWZmaWN1bHQgdG8gYWNjdXJhdGVseSBpZGVudGlmeSBhIHJhY2lhbCBjb21wb25lbnQgdG8gdGhlc2UgaW5qdXJpZXMuIA0KDQojIyMgSGlzcGFuaWMNCg0KDQpgYGB7cn0NCmlmIChzeXN0ZW0uZmlsZShwYWNrYWdlID0gIndhZmZsZSIpID09ICIiKSB7DQogIGluc3RhbGwucGFja2FnZXMoIndhZmZsZSIpDQp9DQoNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkod2FmZmxlKQ0KDQpoY291bnRzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoZGZfbWFwcGVkJGhpc3BhbmljKSkNCmNvbG5hbWVzKGhjb3VudHMpWzFdPC0iaGlzcGFuaWMiDQpjb2xuYW1lcyhoY291bnRzKVsyXTwtImZyZXF1ZW5jeSINCg0KdmVjIDwtIG51bWVyaWMoKQ0KdmVjUyA8LSBjaGFyYWN0ZXIoKQ0KDQpmb3IoaSBpbiBoY291bnRzJGZyZXF1ZW5jeSkNCnsNCiAgICB4IDwtIGkvcm93Y291bnQNCiAgICB4IDwtIHgqMTAwDQogICAgdmVjIDwtIGModmVjLCB4KQ0KICAgIA0KICAgIHMgPC0gc3ByaW50ZigiJS4yZiUlIiwgeCkNCiAgICB2ZWNTIDwtIGModmVjUywgcykNCn0NCg0KaGNvdW50cyA8LSBjYmluZChoY291bnRzLCBuZXdfY29sID0gdmVjKQ0KY29sbmFtZXMoaGNvdW50cylbM108LSJwZXJjZW50Ig0KDQpoY291bnRzIDwtIGNiaW5kKGhjb3VudHMsIG5ld19jb2wgPSB2ZWNTKQ0KY29sbmFtZXMoaGNvdW50cylbNF08LSJsYWJlbHMiDQoNCmdncGxvdChoY291bnRzLCBhZXMoeCA9ICIiLCB5ID0gcGVyY2VudCwgZmlsbCA9IGhpc3BhbmljKSkgKw0KICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHdpZHRoPTMpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGxhYmVscyksIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNFNTk4NjYiLCIjMjdBRTYwIiwgIiNGQ0YzQ0YiKSkgKyAgIA0KICBjb29yZF9wb2xhcigieSIsIHN0YXJ0PTApICsgDQogIGxhYnModGl0bGUgPSAiQnJlYWtkb3duIG9mIHRoZSBIaXNwYW5pYyBQb3B1bGF0aW9uIiwNCiAgICAgICAgICAjc3VidGl0bGUgPSAidGVzdCIsDQogICAgICAgICAgY2FwdGlvbiA9ICJPbmx5IDMlIG9mIHRoZSBwYXRpZW50cyBpZGVudGlmeSBhcyBIaXNwYW5pYyIpDQpgYGANClNvLCB0aGUgbWFqb3JpdHkgb2YgcGF0aWVudHMgYXJlIG5vdCBoaXNwYW5pYywgaG93ZXZlciwgd2UgY2FuJ3QgY29uY2x1ZGUgbm90IGJlaW5nIGhpc3BhbmljIG1ha2VzIGEgcGVyc29uIG1vcmUgbGlrZXkgdG8gZmFsbC4NCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0KI2NsZWFudXANCnJtKHZlYywgdmVjUywgeCwgcywgaGNvdW50cykNCmBgYA0KDQoNCmBgYHtyfQ0KaWYgKHN5c3RlbS5maWxlKHBhY2thZ2UgPSAibW9vbkJvb2siKSA9PSAiIikgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJtb29uQm9vayIpDQp9DQoNCmlmIChzeXN0ZW0uZmlsZShwYWNrYWdlID0gIndlYnIiKSA9PSAiIikgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJ3ZWJyIikNCn0NCg0KbGlicmFyeShtb29uQm9vaykNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkod2VicikNCmxpYnJhcnkoZHBseXIpDQoNCnJoY291bnRzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoZGZfbWFwcGVkJGhpc3BhbmljLCBkZl9tYXBwZWQkcmFjZSkpDQpjb2xuYW1lcyhyaGNvdW50cylbMV08LSJoaXNwYW5pYyINCmNvbG5hbWVzKHJoY291bnRzKVsyXTwtInJhY2UiDQpjb2xuYW1lcyhyaGNvdW50cylbM108LSJmcmVxdWVuY3kiDQoNCndlYnI6OlBpZURvbnV0KHJoY291bnRzLCBhZXMoaGlzcGFuaWMsIHJhY2UsIGNvdW50PWZyZXF1ZW5jeSksIA0KICAgICAgICAgICAgICByMCA9IDAuMywgI2hpZGVzIHRoZSBjZW50ZXINCiAgICAgICAgICAgICAgIHIxID0gMC43LA0KICAgICAgICAgICAgICAgI2V4cGxvZGUgPSAzLA0KICAgICAgICAgICAgICAgI2V4cGxvZGVEb251dCA9IFRSVUUsDQogICAgICAgICAgICAgICBwaWVMYWJlbFNpemUgPSAzLA0KICAgICAgICAgICAgICAgZG9udXRMYWJlbFNpemUgPSA0LA0KICAgICAgICAgICAgICAgdGl0bGUgPSAiSGlzcGFuaWMgYW5kIFJhY2lhbCBCcmVha2Rvd24iKQ0KDQpgYGANCkFzIHdpdGggdGhlIEhpc3BhbmljIHBpZSBjaGFydCwgYW5kIHdpdGggb25seSAzJSBvZiB0aGUgaW5qdXJlZCBzZXQgYmVpbmcgaGlzcGFuaWMsIEknbSBub3QgY29udmluY2VkIHRoYXQgaGlzcGFuaWM9eWVzIGNvcnJlbGF0ZXMgdG8gYSBmYWxsLiBGdXJ0aGVyLCBubyBvbmUgcmFjaWFsIGdyb3VwIHN0YW5kcyBvdXQgQ2VydGFpbmx5LCBwYXJ0IG9mIHRoZSBVbmsvTm90IFN0YXRlZCBncm91cCBpcyBwcm9iYWJseSBoaXNwYW5pYywgYnV0IHdlIGRvbid0IGtub3cgZm9yIGNlcnRhaW4uIEZ1cnRoZXIgb2JmdXNjYXRpbmcgdGhpcyBwYXJ0IG9mIHRoZSBoaXNwYW5pYyBzZXQgaXMgdGhlIE4uUyBwYXJ0IG9mIHRoZSByYWNlIGRhdGEsIHdoaWNoIHJlcHJlc2VudHMgNzYlIG9mIHRoZSBVbmtub3duIGhpc3BhbmljIGdyb3VwLiANCg0KDQpXZSdsbCBjb250aW51ZSB0byBsb29rIGF0IHJhY2UsIGJ1dCBJIGRvbid0IGJlbGlldmUgdGhlcmUgaXMgYW55dGhpbmcgdG8gYmUgZ2FpbmVkIGZyb20gaW5jbHVkaW5nIHRoZSBoaXNwYW5pYyBjb2x1bW4gaW4gb3VyIG1vZGVsLg0KDQoNCg0KYGBge3IsIGlnbm9yZT1UUlVFfQ0Kcm0ocmhjb3VudHMpDQpgYGANCg0KDQoNCiMjIERpYWdub3Npcw0KTmV4dCBpcyBhIGxvb2sgYXQgdGhlIGRpYWdub3NpcyBjb2x1bW4uIFdlJ2xsIHN0YXJ0IG9mZiBieSBsb29raW5nIGZvciB0aGUgbW9zdCBoZWF2aWx5IGRpYWdub3NlZCBpbmp1cmllcy4NCg0KYGBge3J9DQojZ3JvdXBpbmcgdGhlIGRpYWdub3NpcyBjb2x1bW4sIGxvb2tpbmcgZm9yIHRoZSBtb3N0IGZyZXF1ZW50IGluanVyeQ0KDQojI2ZyZXF1ZW5jeSBvZiBlYWNoIGRpYWdub3Npcw0KZGNvdW50cyA8LWRmX21hcHBlZFssIGMoJ2RpYWdub3NpcycpXQ0KDQpkZl9kaWFnbm9zaXNmcmVxIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoZGNvdW50cykpDQpjb2xuYW1lcyhkZl9kaWFnbm9zaXNmcmVxKVsxXSA8LSAiZGlhZ25vc2lzX2NvZGUiIA0KY29sbmFtZXMoZGZfZGlhZ25vc2lzZnJlcSlbMl0gPC0gImZyZXF1ZW5jeSIgDQoNCiNzb3J0IHRoZSBkYXRhIGluIGRlc2NlbmRpbmcgb3JkZXINCmRmX2RpYWdub3Npc2ZyZXFTb3J0ZWQgPC0gZGZfZGlhZ25vc2lzZnJlcVtvcmRlcigtZGZfZGlhZ25vc2lzZnJlcSRmcmVxdWVuY3kpLF0NCmhlYWQoZGZfZGlhZ25vc2lzZnJlcVNvcnRlZCkNCg0KI2NsZWFudXANCnJtKGRjb3VudHMsIGRmX2RpYWdub3Npc2ZyZXEpDQpgYGANCkZyb20gdGhpcyBzb3J0aW5nLCB3ZSBrbm93IHRoYXQgZnJhY3R1cmVzLCBpbnRlcm5hbCBpbmp1cmllcywgY29udHVzaW9ucyBhYmosIGFuZCBsYWNlcnRhdGlvbnMgbWFrZSB1cCB0aGUgbWFqb3JpdHkgb2YgdGhlIDI2IGxpc3RlZCBpbmp1cmllcyBieSBhIHNpZ25pZmljYW50IGFtb3VudC4NCg0KYGBge3J9DQojYmFzZWQgb24gdGhlIGZyZXF1ZW5jeSBvZiB0aGlzIHBsb3QsIHdlIGNhbiBzZWUgdGhhdCB0aGUgZmlyc3QgNCBpdGVtcyByZXByZXNlbnQgdGhlIG1ham9yaXR5IG9mIHRoZSBkaWFnbm9zaXMNCiNsZXRzIGxvb2sgYXQgdGhlIHBlcmNlbnRhZ2Ugb2YgdGhlIGNhc2VzDQoNCmhpZ2hlc3Q0ZGlhZ25vc2lzIDwtIHN1bShkZl9kaWFnbm9zaXNmcmVxU29ydGVkJGZyZXF1ZW5jeVsxOjRdKSAjIFRoaXMgZXF1YWxzIDk5LDg2OA0KcGVyY2VudG9mdG9wNGRpYWdub3NpcyA8LSBoaWdoZXN0NGRpYWdub3Npcy9yb3djb3VudCAgICAjMTE1MTI4PXRvdGFsIGluanVyaWVzIDg2LjclDQpwcmludChzcHJpbnRmKCJQZXJjZW50YWdlIG9mIHRoZSB0b3AgNCBpbmp1cmllcyBpczogJWYlJSwgb3IgJWkgdG90YWwgcmVwb3J0ZWQgaW5qdXJpZXMuIiwgcGVyY2VudG9mdG9wNGRpYWdub3NpcyoxMDAsIGhpZ2hlc3Q0ZGlhZ25vc2lzKSkNCg0KDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHdhZmZsZSkNCg0KDQpybSh2ZWMsIHZlY3MpDQoNCnZlYyA8LSBudW1lcmljKCkNCnZlY1MgPC0gY2hhcmFjdGVyKCkNCnZlY0NvbG9yIDwtIGNoYXJhY3RlcigpDQoNCm4gPC0gbnJvdyhkZl9kaWFnbm9zaXNmcmVxU29ydGVkKQ0KDQpmb3IoaSBpbiAxOm4pDQp7DQogICAgcm93IDwtIGRmX2RpYWdub3Npc2ZyZXFTb3J0ZWRbaSwgXQ0KICAgIA0KICAgIGNvZGUgPC0gYXMuY2hhcmFjdGVyKHJvdyRkaWFnbm9zaXNfY29kZSkNCiAgICBmcmVxIDwtIGFzLmludGVnZXIocm93JGZyZXF1ZW5jeSkNCiAgICANCiAgICBwcmludChjKGNvZGUsIGZyZXEpKQ0KICAgIA0KICAgIHBlcmMgPC0gKGZyZXEvcm93Y291bnQpKjEwMA0KICAgIA0KICAgIHZlYyA8LSBjKHZlYywgcGVyYykgI2FkZCB2YWx1ZSB0byBhIHZlY3Rvcg0KICAgIHNEaWFnIDwtIGlmZWxzZSgocGVyYyA+IDEwLjApLCBzcHJpbnRmKCIlcyIsIGNvZGUpLCAiIikjZGlzcGxheSBvbmx5IG1lYW5pbmcgdmFsdWVzIG9uIHRoZSBwaWUgY2hhcnQNCiAgICB2ZWNTIDwtIGModmVjUywgc0RpYWcpDQogICAgDQogICAgc0NvbG9yIDwtIGlmZWxzZSgoaSA8IDUpLCAiI0FBMDAwMCIsICIjMDAwMEFBIikNCiAgICB2ZWNDb2xvciA8LSBjKHZlY0NvbG9yLCBzQ29sb3IpICAgICAgICAgICAgICAgICAgICAgDQp9I2VuZCBvZiBhcHBseQ0KDQoNCmRmX2RpYWdub3Npc2ZyZXFTb3J0ZWQgPC0gY2JpbmQoZGZfZGlhZ25vc2lzZnJlcVNvcnRlZCwgbmV3X2NvbCA9IHZlYykNCmNvbG5hbWVzKGRmX2RpYWdub3Npc2ZyZXFTb3J0ZWQpWzNdPC0icGVyY2VudCINCg0KZGZfZGlhZ25vc2lzZnJlcVNvcnRlZCA8LSBjYmluZChkZl9kaWFnbm9zaXNmcmVxU29ydGVkLCBuZXdfY29sID0gdmVjUykNCmNvbG5hbWVzKGRmX2RpYWdub3Npc2ZyZXFTb3J0ZWQpWzRdPC0ibGFiZWxzIg0KDQpkZl9kaWFnbm9zaXNmcmVxU29ydGVkIDwtIGNiaW5kKGRmX2RpYWdub3Npc2ZyZXFTb3J0ZWQsIG5ld19jb2wgPSB2ZWNDb2xvcikNCmNvbG5hbWVzKGRmX2RpYWdub3Npc2ZyZXFTb3J0ZWQpWzVdPC0iY29sb3JzIg0KDQpnZ3Bsb3QoZGZfZGlhZ25vc2lzZnJlcVNvcnRlZCwgYWVzKHggPSAiIiwgeSA9IGZyZXF1ZW5jeSwgZmlsbCA9IGRpYWdub3Npc19jb2RlKSkgKw0KICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHdpZHRoPTEpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGxhYmVscyksIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpKSArDQogICNzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBkZl9kaWFnbm9zaXNmcmVxU29ydGVkJGNvbG9ycykgKw0KICBjb29yZF9wb2xhcigieSIsIHN0YXJ0PTApDQoNCmBgYA0KU2VlaW5nIHRoZSBtYWpvcml0eSAoODYlKSBvZiB0aGUgZGF0YXNldCBpcyBkaWFnbm9zZWQgd2l0aCB0aGVzZSA0IGluanVyaWVzIChmcmFjdHVyZXMsIGludGVybmFsIGluanVyaWVzLCBjb250dXNpb25zIGFiaiwgYW5kIGxhY2VydGF0aW9ucyksIG91ciBmb2N1cyB3aWxsIGJlIG9uIGhvdyBhZ2UsIHJhY2UgYW5kIGxvY2F0aW9uIHBsYXkgYSBwYXJ0IHdpdGggdGhlc2UgaW5qdXJpZXMuDQoNCmBgYHtyLCBpZ25vcmU9VFJVRX0NCiNjbGVhbnVwDQpybSh2ZWMsIHZlY1MsIHZlY0NvbG9yLCBkZl9kaWFnbm9zaXNmcmVxU29ydGVkKQ0KYGBgDQojIyMgRmlyZSBJbnZvbHZlbWVudCBhbmQgQWxjb2hvbA0KUmVsYXRlZCB0byB0aGUgaW5qdXJpZXMgYXJlIHRoZSBjYXNlcyBvZiBidXJucyBhbmQgYWxjb2hvbCBoYXZpbmcgYW4gZWZmZWN0IG9uIHRoZSBmYWxsaW5nIGluanVyaWVzLiBMZXQncyB0YWtlIGEgbG9vayB0byBzZWUgaG93IHRoZSBwYXRpZW50IHBvcHVsYXRpb24gaW4gdGhpcyBkYXRhc2V0IGhhcyBiZWVuIGFmZmVjdGVkIGJ5IHRoZW0uV2Uga25vdyBmcm9tIHRoZSBkaWFnbm9zaXMgZnJlcXVlbmNpZXMsIHRoYXQgYnVybiBpbmp1cmllcyANCg0KIyMjIyBGaXJlIEludm9sdmVtZW50DQpgYGB7cn0NCiMjZnJlcXVlbmN5IG9mIHRoZSBidXJuIGRpYWdub3Npcw0KYnVybmNvdW50cyA8LSBzcWxkZignU0VMRUNUIGRpYWdub3NpcywgY291bnQoZGlhZ25vc2lzKSBBUyAiZnJlcXVlbmN5Ig0KICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSBkZl9tYXBwZWQNCiAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFIChkaWFnbm9zaXMgPSAiNDcgLSBCVVJOLCBOT1QgU1BFQy4iIG9yIGRpYWdub3NpcyA9ICI0OSAtIEJVUk4sIENIRU1JQ0FMIiBvciBkaWFnbm9zaXMgPSAiNDggLSBCVVJOLCBTQ0FMRCIgb3IgZGlhZ25vc2lzID0gIjUxIC0gQlVSTlMsIFRIRVJNQUwiKQ0KICAgICAgICAgICAgICAgICAgICAgICAgR1JPVVAgQlkgZGlhZ25vc2lzDQogICAgICAgICAgICAgICAgICAgICAgICBPUkRFUiBCWSBmcmVxdWVuY3kgREVTQycpDQoNCmhlYWQoYnVybmNvdW50cykNCg0KDQojI2ZyZXF1ZW5jeSBvZiBmaXJlX2ludm9sdmVtZW50DQpmY291bnRzIDwtZGZfbWFwcGVkWywgYygnZmlyZV9pbnZvbHZlbWVudCcpXQ0KDQpkZl9maXJlZnJlcSA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKGZjb3VudHMpKQ0KY29sbmFtZXMoZGZfZmlyZWZyZXEpWzFdIDwtICJmaXJlX2ludm9sdmVtZW50IiANCmNvbG5hbWVzKGRmX2ZpcmVmcmVxKVsyXSA8LSAiZnJlcXVlbmN5IiANCg0KI3NvcnQgdGhlIGRhdGEgaW4gZGVzY2VuZGluZyBvcmRlcg0KZGZfRmlyZUlzRnJlcVNvcnRlZCA8LSBkZl9maXJlZnJlcVtvcmRlcigtZGZfZmlyZWZyZXEkZnJlcXVlbmN5KSxdDQpoZWFkKGRmX0ZpcmVJc0ZyZXFTb3J0ZWQpDQoNCiNjbGVhbnVwDQpybShidXJuY291bnRzLCBmY291bnRzLCBkZl9maXJlZnJlcSwgZGZfRmlyZUlzRnJlcVNvcnRlZCkNCmBgYA0KRnJvbSB0aGVzZSBudW1iZXJzLCB3ZSBzZWUgdGhlcmUgaXMgdmVyeSBmZXcgYnVybiBpbmp1cmllcy4gRWlnaHR5b25lIHRvdGFsLCBvciAwLjclIG9mIHRoZSB0b3RhbCBkYXRhc2V0LiBGb3IgdGhpcyBwcm9qZWN0LCB3ZSB3b24ndCBleHBsb3JlIGJ1cm4gaW5qdXJpZXMgb3IgZmlyZSBpbnZvbHZlbWVudCBmdXJ0aGVyIGJlY2F1c2UgdGhpcyBpcyBzdWNoIGEgc21hbGwgcGFydCBvZiB0aGUgcG9wdWxhdGlvbi4NCg0KIyMjIyBBbGNvaG9sDQpVbmxpa2UgdGhlIGJ1cm5zIGFuZCBmaXJlIGludm9sdmVtZW50LCB0aGVyZSBpc24ndCBhIHNldCBvZiBpbmp1cmllcyB0aGF0IHNwZWNpZmljYWxseSBjb25uZWN0cyB3aXRoIGFsY29ob2wgdXNhZ2UuIFNvLCBpZiB3ZSBzZWUgYSBsYXJnZSBudW1iZXIgb2YgcGF0aWVudHMgdGhhdCByZXBvcnRlZCBhbGNvaG9sIHVzYWdlLCBpdCB3aWxsIGJlIGludGVyZXN0aW5nIHRvIHNlZSB3aGljaCBkaWFnbm9zaXMgd2VyZSB0aWVkIHRvIGl0Lg0KDQpgYGB7cn0NCiMjZnJlcXVlbmN5IG9mIHRoZSBidXJuIGRpYWdub3Npcw0KYWxjb2hvbGNvdW50cyA8LSBzcWxkZignU0VMRUNUIGFsY29ob2wsIGNvdW50KGFsY29ob2wpIEFTICJmcmVxdWVuY3kiDQogICAgICAgICAgICAgICAgICAgICAgICBGUk9NIGRmX21hcHBlZA0KICAgICAgICAgICAgICAgICAgICAgICAgR1JPVVAgQlkgYWxjb2hvbA0KICAgICAgICAgICAgICAgICAgICAgICAgT1JERVIgQlkgZnJlcXVlbmN5IERFU0MnKQ0KDQpoZWFkKGFsY29ob2xjb3VudHMpDQoNCnllc3RvdGFsIDwtIGFsY29ob2xjb3VudHNbMiwyXQ0KDQpwZXJjZW50IDwtIHllc3RvdGFsL3Jvd2NvdW50KjEwMA0KcHJpbnQoc3ByaW50ZigiUGVyY2VudGFnZSBvZiBjYXNlcyB3aGVyZSBhbGNvaG9sIHdhcyByZWxhdGVkIHRvIHRoZSBmYWxsaW5nIGluanVyeTogJS4yZiUlLiIsIHBlcmNlbnQpKQ0KI2NsZWFudXANCnJtKGFsY29ob2xjb3VudHMsIHllc3RvdGFsLCBwZXJjZW50KQ0KYGBgDQpUaGUgbnVtYmVyIG9mIGFsY29ob2wgcmVsYXRlZCBjYXNlcyBpcyAyNTg4LCBvciAyLjI1JSBvZiB0aGUgcGF0aWVudHMgaW4gdGhlIGRhdGFzZXQuIEZvciB0aGlzIHByb2plY3QsIHdlIHdvbid0IGV4cGxvcmUgYWxjb2hvbCBmdXJ0aGVyIGJlY2F1c2UgdGhpcyByZXByZXNlbnRzIGEgc21hbGwgcGFydCBvZiB0aGUgcG9wdWxhdGlvbi4NCg0KIyMgTG9jYXRpb25zIFdoZXJlIFBhdGllbnRzIFJlcG9ydGVkIEdldHRpbmcgSHVydA0KSSB3YW50IHRvIHRha2UgYSBxdWljayBsb29rIGF0IHdoZXJlIHBlb3BsZSBhcmUgZ2V0dGluZyBodXJ0LiBUaGlzIGNvdWxkIGltcGFjdCBob3cgd2UgbG9vayBmb3IgY29ycmVsYXRpb25zIGxhdGVyIG9uLg0KDQpgYGB7cn0NCg0KbG9jYXRpb25yZXN1bHRzIDwtIHNxbGRmKCdTRUxFQ1QgbG9jYXRpb24sIGNvdW50KGxvY2F0aW9uKSBBUyAiZnJlcXVlbmN5Ig0KICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSBkZl9tYXBwZWQNCiAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFIChkaWFnbm9zaXMgPSAiNTMgLSBDT05UVVNJT05TLCBBQlIuIiBvciBkaWFnbm9zaXMgPSAiNTcgLSBGUkFDVFVSRSIgb3IgZGlhZ25vc2lzID0gIjU5IC0gTEFDRVJBVElPTiIgb3IgZGlhZ25vc2lzID0gIjYyIC0gSU5URVJOQUwgSU5KVVJZIikNCiAgICAgICAgICAgICAgICAgICAgICAgIEdST1VQIEJZIGxvY2F0aW9uJykNCg0KcGllKGxvY2F0aW9ucmVzdWx0cyRmcmVxdWVuY3ksIGxhYmVscyA9IGxvY2F0aW9ucmVzdWx0cyRsb2NhdGlvbiwgbWFpbj0iTG9jYXRpb24gQnJlYWtkb3duIikNCg0KI3BlcmNlbnRvZmZlbWFsZXMgPC0gKGdlbnRhYmxlWzIsICdGcmVxJ10vcm93Y291bnQqMTAwKQ0KI3V0IDwtIHNwcmludGYoIlBlcmNlbnRhZ2Ugb2YgZmVtYWxlcyBpbiB0aGlzIGRhdGFzZXQ6ICVmKSIsIHBlcmNlbnRvZmZlbWFsZXMpICNwZXJjZW50YWdlIG9mIGZlbWFsZXMgaW4gdGhpcyBkYXRhc2V0DQojb3V0DQpgYGANClRoaXMgcGllIGNoYXJ0IGlzbid0IHRoZSBwcmV0dGllc3QsIGJ1dCBpdCBkb2VzIGNsZWFybHkgc2hvdyB0aGF0IEhvbWUgaXMgdGhlIHByaW1hcnkgbG9jYXRpb24gd2hlcmUgaW5qdXJpZXMgdGFrZSBwbGFjZS4gVGhpcyBpcyBmb2xsb3dlZCB1cCBieSBQdWJsaWMgYW5kIFVua25vd24uIFVua25vd24gaXMgYSBmcnVzdHJhdGluZyByZXN1bHQgZm9yIHRoaXMgcG9ydGlvbiBvZiB0aGUgZGF0YSwgYmVjYXVzZSBpdCBpc24ndCBjbGVhciBob3cgdG8gbWl0aWdhdGUgcHJvYmxlbXMgYXQgdGhpcyBsb2NhdGlvbi4NCg0KDQojIyBEaWFnbm9zaXMsIFJhY2UsIGFuZCBHZW5kZXINCkxldCdzIGxvb2sgdG8gc2VlIGlmIHRoZXJlIGlzIGFueSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBpbmp1cmllcywgcmFjZSwgYW5kIGdlbmRlciwgd2l0aCB0aGUgZm9jdXMgYmVpbmcgb24gdGhlIHRvcCA0IGluanVyaWVzIGlkZW50aWZpZWQgYWJvdmUuDQoNCmBgYHtyfQ0KaWYgKHN5c3RlbS5maWxlKHBhY2thZ2UgPSAic3FsZGYiKSA9PSAiIikgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJzcWxkZiIpDQp9DQoNCmxpYnJhcnkoc3FsZGYpDQpsaWJyYXJ5KHBseXIpDQpsaWJyYXJ5KGRwbHlyKQ0KDQojZnJlcXVlbmN5IG9mIGVhY2ggZGlhZ25vc2lzIGJ5IGdlbmRlcg0KcmVzdWx0cyA8LSBzcWxkZignU0VMRUNUIGRpYWdub3Npcywgc2V4LCBjb3VudCgqKSBBUyAiZnJlcXVlbmN5Ig0KICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSBkZl9tYXBwZWQNCiAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFIChkaWFnbm9zaXMgPSAiNTMgLSBDT05UVVNJT05TLCBBQlIuIiBvciBkaWFnbm9zaXMgPSAiNTcgLSBGUkFDVFVSRSIgb3IgZGlhZ25vc2lzID0gIjU5IC0gTEFDRVJBVElPTiIgb3IgZGlhZ25vc2lzID0gIjYyIC0gSU5URVJOQUwgSU5KVVJZIikNCiAgICAgICAgICAgICAgICAgICAgICAgIEdST1VQIEJZIGRpYWdub3Npcywgc2V4DQogICAgICAgICAgICAgICAgICAgICAgICBPUkRFUiBCWSBkaWFnbm9zaXMsIHNleCwgZnJlcXVlbmN5IERFU0MnKQ0KDQoNCiNwbG90IHRoZW0NCmdncGxvdChyZXN1bHRzKSArIA0KICAgIGdlb21fY291bnQobWFwcGluZyA9IGFlcyh4PWRpYWdub3NpcywgeT1mcmVxdWVuY3ksIGNvbG9yPXNleCkpICsgDQogICAgbGFicyh0aXRsZSA9ICJGcmVxdWVuY3kgb2YgSW5qdXJ5IEJ5IERpYWdub3NpcyAmIEdlbmRlciIsIHg9IkRpYWdub3NpcyIsIHk9IkNvdW50IikNCmBgYA0KIEZyb20gdGhpcyBwbG90LCB3ZSBjYW4gc2VlIHRoYXQgd29tZW4gYXJlIHNldmVyZWx5IGRpYWdub3NlZCB3aXRoICI1NyAtIEZyYWN0dXJlcyIgYW5kICI2MyAtIEludGVybmFsIEluanVyeSI7IGhvd2V2ZXIsIHdvbWVuIHN1ZmZlciBmcm9tIGFsbCBvZiB0aGVzZSB0b3AgZGlhZ25vc2lzIG1vcmUgdGhhbiBtZW4uICoqU28gc3BlY2lhbCBhdHRlbnRpb24qKiBoYXMgdG8gYmUgcGFpZCBmb3IgYWRkcmVzc2luZyB0aGUgZmFjdG9ycyBhZmZlY3Rpbmcgd29tZW4uDQogDQojIyBEaWFnbm9zaXMsIFNleCAoR2VuZGVyKSwgYW5kIExvY2F0aW9uIA0KU28gZmFyLCB3ZSd2ZSBzZWVuIGluZGl2aWR1YWwgYnJlYWtkb3ducyBvZiB0aGUgZGF0YSwgYnV0IGxldCdzIHN0YXJ0IG1peGluZyB1cCB0aGUgY29sdW1ucyBpbiB0aGUgaG9wZXMgb2YgZXhwb3NpbmcgYSBjdWxwcmV0ZSB0byB0aGUgcHJvYmxlbS4NCg0KYGBge3J9DQpsb2NhdGlvbnJlc3VsdHMgPC0gc3FsZGYoJ1NFTEVDVCBsb2NhdGlvbiwgZGlhZ25vc2lzLCBzZXgsIGNvdW50KHNleCkgQVMgImZyZXF1ZW5jeSINCiAgICAgICAgICAgICAgICAgICAgICAgIEZST00gZGZfbWFwcGVkDQogICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAoZGlhZ25vc2lzID0gIjUzIC0gQ09OVFVTSU9OUywgQUJSLiIgb3IgZGlhZ25vc2lzID0gIjU3IC0gRlJBQ1RVUkUiIG9yIGRpYWdub3NpcyA9ICI1OSAtIExBQ0VSQVRJT04iIG9yIGRpYWdub3NpcyA9ICI2MiAtIElOVEVSTkFMIElOSlVSWSIpDQogICAgICAgICAgICAgICAgICAgICAgICBHUk9VUCBCWSBsb2NhdGlvbiwgZGlhZ25vc2lzLCBzZXgnKQ0Kc3VtKGxvY2F0aW9ucmVzdWx0cyRmcmVxdWVuY3kpICNyZXN1bHRzID0gOTk4NjgNCiAgICAjPC0gICAgZGZfZmlyZWZyZXFbb3JkZXIoLWRmX2ZpcmVmcmVxJGZyZXF1ZW5jeSksXQ0Kc29ydGVkIDwtIGxvY2F0aW9ucmVzdWx0c1tvcmRlcigtbG9jYXRpb25yZXN1bHRzJGZyZXF1ZW5jeSksXQ0KDQpoZWFkKHNvcnRlZCkNCg0Kcm0obG9jYXRpb25yZXN1bHRzLCBzb3J0ZWQpDQoNCmBgYA0KVGhpcyByZXN1bHQgaXMgaW50ZXJlc3RpbmcgYmVjYXVzZSB3ZSBzZWUgdGhhdCBmcmFjdHVyZXMgYW5kIGludGVybmFsIGluanVyaWVzIGFmZmVjdCB3b21lbiBieSBhIHNpZ25pZmljYW50IGFtb3VudCAqKmF0IGhvbWUqKi4NCg0KDQojIExvY2F0aW9uLCBEaWFnbm9zaXMsIEJvZHkgUGFydA0KTm93IHRoYXQgd2UndmUgaWRlbnRpZmllZCBmZW1hbGVzIGFyZSBiZWluZyBkaXNwcm9wb3J0aW9uYWwgaHVydCBhdCBob21lLCB3aGljaCBib2R5X3BhcnQgaXMgYWZmZWN0ZWQgdGhlIG1vc3Q/IA0KDQpJJ20gZm9jdXNlZCBvbiB0aGUgd29tZW4sIGhvd2V2ZXIsIGxldCdzIGNvbnRpbnVlIHRvIGxvb2sgYXQgbWVuIGluIHRoZSBxdWVyeS4NCmBgYHtyfQ0KbG9jYXRpb25yZXN1bHRzIDwtIHNxbGRmKCdTRUxFQ1QgbG9jYXRpb24sIGRpYWdub3NpcywgYm9keV9wYXJ0LCBzZXgsIGNvdW50KHNleCkgQVMgImZyZXF1ZW5jeSINCiAgICAgICAgICAgICAgICAgICAgICAgIEZST00gZGZfbWFwcGVkDQogICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAoZGlhZ25vc2lzID0gIjUzIC0gQ09OVFVTSU9OUywgQUJSLiIgb3IgZGlhZ25vc2lzID0gIjU3IC0gRlJBQ1RVUkUiIG9yIGRpYWdub3NpcyA9ICI1OSAtIExBQ0VSQVRJT04iIG9yIGRpYWdub3NpcyA9ICI2MiAtIElOVEVSTkFMIElOSlVSWSIpDQogICAgICAgICAgICAgICAgICAgICAgICBHUk9VUCBCWSBsb2NhdGlvbiwgZGlhZ25vc2lzLCBib2R5X3BhcnQsICBzZXgnKQ0Kc3VtKGxvY2F0aW9ucmVzdWx0cyRmcmVxdWVuY3kpICNyZXN1bHRzID0gOTk4NjgNCiAgICAjPC0gICAgZGZfZmlyZWZyZXFbb3JkZXIoLWRmX2ZpcmVmcmVxJGZyZXF1ZW5jeSksXQ0Kc29ydGVkIDwtIGxvY2F0aW9ucmVzdWx0c1tvcmRlcigtbG9jYXRpb25yZXN1bHRzJGZyZXF1ZW5jeSksXQ0KDQpoZWFkKHNvcnRlZCkNCg0KYGBgDQpUaGVzZSByZXN1bHRzIGFyZSBoZWxwZnVsLiBQcmV2aW91c2x5IHdlIHNhdyBmcmFjdHVyZXMgYXQgdGhlIG1vc3Qgc2VyaW91cyBwcm9ibGVtLiBIb3dldmVyLCB3aGVuIHdlIGZhY3RvciBpbiB0aGUgYm9keV9wYXJ0IHdlIHNlZSB0aGUgaW50ZXJuYWwgaW5qdXJpZXMgdG8gdGhlIGhlYWQgYXQgaG9tZSBhbmQgaW4gdGhlIHB1YmxpYyBsb2NhdGlvbiBpcyB0aGUgbW9zdCBzZXJpb3VzIHByb2JsZW0NCg0KYGBge3IsIGlnbm9yZT1UUlVFfQ0Kcm0obG9jYXRpb25yZXN1bHRzLCBzb3J0ZWQpDQpgYGANCg0KTGV0J3MgbG9vayBhdCB0aGlzIHNhbWUgZGF0YSB3aXRoIGp1c3QgdGhlIHdvbWVuLg0KYGBge3J9DQoNCmxvY2F0aW9ucmVzdWx0cyA8LSBzcWxkZignU0VMRUNUIGxvY2F0aW9uLCBkaWFnbm9zaXMsIGJvZHlfcGFydCwgc2V4LCBjb3VudChzZXgpIEFTICJmcmVxdWVuY3kiDQogICAgICAgICAgICAgICAgICAgICAgICBGUk9NIGRmX21hcHBlZA0KICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgKGRpYWdub3NpcyA9ICI1MyAtIENPTlRVU0lPTlMsIEFCUi4iIG9yIGRpYWdub3NpcyA9ICI1NyAtIEZSQUNUVVJFIiBvciBkaWFnbm9zaXMgPSAiNTkgLSBMQUNFUkFUSU9OIiBvciBkaWFnbm9zaXMgPSAiNjIgLSBJTlRFUk5BTCBJTkpVUlkiKSBBTkQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHNleCA9ICJGRU1BTEUiKQ0KICAgICAgICAgICAgICAgICAgICAgICAgR1JPVVAgQlkgbG9jYXRpb24sIGRpYWdub3NpcywgYm9keV9wYXJ0LCAgc2V4JykNCnN1bShsb2NhdGlvbnJlc3VsdHMkZnJlcXVlbmN5KSAjcmVzdWx0cyA9IDk5ODY4DQogICAgIzwtICAgIGRmX2ZpcmVmcmVxW29yZGVyKC1kZl9maXJlZnJlcSRmcmVxdWVuY3kpLF0NCnNvcnRlZCA8LSBsb2NhdGlvbnJlc3VsdHNbb3JkZXIoLWxvY2F0aW9ucmVzdWx0cyRmcmVxdWVuY3kpLF0NCg0KaGVhZChzb3J0ZWQpDQoNCmBgYA0KRnJvbSB0aGlzIHRhYmxlLCB3ZSBzZWUgdGhhdCB3aGVuIHRoZSBkaWFnbm9zaXMgaXMgYW4gaW50ZXJuYWwgaW5qdXJ5LCB0aGUgaGVhZCBpcyB0aGUgYm9keSBwYXJ0IGluanVyaWVkIHRoZSBtb3N0LiBIb21lIGlzIHRoZSBtb3N0IGxpa2VseSBwbGFjZSBmb3IgdGhlIGluanVyaWVzLCBmb2xsb3dlZCBieSB0aGUgcHVibGljIG9yIHVua25vd24gbG9jYXRpb25zLiBOZXh0IG1vc3QgZnJlcXVlbnQgaW5qdXJ5IGlzIHRoZSB1cHBlciBvciBsb3dlciB0cnVuayBleHBlcmllbmNpbmcgZnJhY3R1cmVzLg0KDQpMZXQgZG8gYSBzaW1pbGFyIHF1ZXJ5IGZvciB0aGUgbWFsZXMgdG8gc2VlIGhvdyB0aGV5IGFyZSBhZmZlY3RlZC4NCmBgYHtyfQ0KDQpsb2NhdGlvbnJlc3VsdHMgPC0gc3FsZGYoJ1NFTEVDVCBsb2NhdGlvbiwgZGlhZ25vc2lzLCBib2R5X3BhcnQsIHNleCwgY291bnQoc2V4KSBBUyAiZnJlcXVlbmN5Ig0KICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSBkZl9tYXBwZWQNCiAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFIChkaWFnbm9zaXMgPSAiNTMgLSBDT05UVVNJT05TLCBBQlIuIiBvciBkaWFnbm9zaXMgPSAiNTcgLSBGUkFDVFVSRSIgb3IgZGlhZ25vc2lzID0gIjU5IC0gTEFDRVJBVElPTiIgb3IgZGlhZ25vc2lzID0gIjYyIC0gSU5URVJOQUwgSU5KVVJZIikgQU5EDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChzZXggPSAiTUFMRSIpDQogICAgICAgICAgICAgICAgICAgICAgICBHUk9VUCBCWSBsb2NhdGlvbiwgZGlhZ25vc2lzLCBib2R5X3BhcnQsICBzZXgnKQ0Kc3VtKGxvY2F0aW9ucmVzdWx0cyRmcmVxdWVuY3kpICNyZXN1bHRzID0gOTk4NjgNCiAgICAjPC0gICAgZGZfZmlyZWZyZXFbb3JkZXIoLWRmX2ZpcmVmcmVxJGZyZXF1ZW5jeSksXQ0Kc29ydGVkIDwtIGxvY2F0aW9ucmVzdWx0c1tvcmRlcigtbG9jYXRpb25yZXN1bHRzJGZyZXF1ZW5jeSksXQ0KDQpoZWFkKHNvcnRlZCkNCg0KYGBgDQpUaGUgcmVzdWx0cyBmb3IgbWVuIGFyZSB2ZXJ5IHNpbWlsYXIgaW4gdGhhdCBpbnRlcm5hbCBpbmp1cmllcyB0byB0aGUgaGVhZCBhcmUgaGl0IHRoZSBtYWxlIHBvcHVsYXRpb24gd2l0aCB0aGUgZ3JlYXRlc3QgZnJlcXVlbmN5LiBBbHNvLCBsaWtlIHRoZSBmZW1hbGVzLCB3ZSBzZWUgdGhhdCBtYWxlcyBleHBlcmllbmNlIHRoZSBmcmFjdHVyZXMgdG8gdGhlIGxvd2VyIGFuZCB1cHBlciB0cnVuayBtb3N0IGZyZXF1ZW50bHkgKGFmdGVyIHRoZSBoZWFkIGluanVyaWVzKSwgYW5kIHRoZSBtYWpvciBvZiB0aGVzZSBpbmp1cmllcyBhcmUgYXQgaG9tZS4NCg0KIyMgQ29ubmVjdGlvbnMgdG8gUHJvZHVjdHM/DQpOZXh0LCBsZXQncyBzZWUgaWYgdGhlcmUgaXMgYSB0aWUgdG8gdGhlIHByb2R1Y3RzLg0KDQpgYGB7cn0NCg0KbG9jYXRpb25yZXN1bHRzIDwtIHNxbGRmKCdTRUxFQ1QgbG9jYXRpb24sIGRpYWdub3NpcywgYm9keV9wYXJ0LCBwcm9kdWN0XzEsICBzZXgsIGNvdW50KHNleCkgQVMgImZyZXF1ZW5jeSINCiAgICAgICAgICAgICAgICAgICAgICAgIEZST00gZGZfbWFwcGVkDQogICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAoZGlhZ25vc2lzID0gIjUzIC0gQ09OVFVTSU9OUywgQUJSLiIgb3IgZGlhZ25vc2lzID0gIjU3IC0gRlJBQ1RVUkUiIG9yIGRpYWdub3NpcyA9ICI1OSAtIExBQ0VSQVRJT04iIG9yIGRpYWdub3NpcyA9ICI2MiAtIElOVEVSTkFMIElOSlVSWSIpDQogICAgICAgICAgICAgICAgICAgICAgICBHUk9VUCBCWSBsb2NhdGlvbiwgZGlhZ25vc2lzLCBib2R5X3BhcnQsIHByb2R1Y3RfMSwgIHNleCcpDQojc3VtKGxvY2F0aW9ucmVzdWx0cyRmcmVxdWVuY3kpICNyZXN1bHRzID0gOTk4NjgNCiAgICAjPC0gICAgZGZfZmlyZWZyZXFbb3JkZXIoLWRmX2ZpcmVmcmVxJGZyZXF1ZW5jeSksXQ0Kc29ydGVkIDwtIGxvY2F0aW9ucmVzdWx0c1tvcmRlcigtbG9jYXRpb25yZXN1bHRzJGZyZXF1ZW5jeSksXQ0KDQpoZWFkKHNvcnRlZCkNCg0KYGBgDQpUaGlzIHF1ZXJ5IHNob3dzIHRoZSBtYWpvcml0eSBvZiBwcm9kdWN0cyBhcmUgdGllZCB0byBmbG9vcnMgb3IgZmxvb3JpbmcgbWF0ZXJpYWxzLiBEb2VzIHRoaXMgbWVhbiB0aGUgcGF0aWVudCBqdXN0IGZlbGwgb24gdGhlIGZsb29yIGxlYWRpbmcgdG8gdGhlIGludGVybmFsIGluanVyaWVzIGFuZCBmcmFjdHVyZXM/IEFsc28gb2Ygbm90ZSBob21lLCBpbnRlcm5hbCBpbmp1cnksIGFuZCBoZWFkcyBhcmUgdGhlIG1vc3QgbGlrZWx5IHRvIGJlIHRoZSBjb21iaW5hdGlvbiBmb3Igb3VyIHBhdGllbnRzLiBMZXQncyBsb29rIGF0IHRoZSBzYW1lIGRhdGEgd2l0aCBqdXN0IHRoZSBmbG9vcnMuDQoNCmBgYHtyfQ0KDQpsb2NhdGlvbnJlc3VsdHMgPC0gc3FsZGYoJ1NFTEVDVCBsb2NhdGlvbiwgZGlhZ25vc2lzLCBib2R5X3BhcnQsIHByb2R1Y3RfMSwgIGNvdW50KHByb2R1Y3RfMSkgQVMgImZyZXF1ZW5jeSINCiAgICAgICAgICAgICAgICAgICAgICAgIEZST00gZGZfbWFwcGVkDQogICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAoZGlhZ25vc2lzID0gIjUzIC0gQ09OVFVTSU9OUywgQUJSLiIgb3IgZGlhZ25vc2lzID0gIjU3IC0gRlJBQ1RVUkUiIG9yIGRpYWdub3NpcyA9ICI1OSAtIExBQ0VSQVRJT04iIG9yIGRpYWdub3NpcyA9ICI2MiAtIElOVEVSTkFMIElOSlVSWSIpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFORCAocHJvZHVjdF8xID0gIjE4MDcgLSBGTE9PUlMgT1IgRkxPT1JJTkcgTUFURVJJQUxTIikNCiAgICAgICAgICAgICAgICAgICAgICAgIEdST1VQIEJZIGxvY2F0aW9uLCBkaWFnbm9zaXMsIGJvZHlfcGFydCwgcHJvZHVjdF8xJykNCnNvcnRlZCA8LSBsb2NhdGlvbnJlc3VsdHNbb3JkZXIoLWxvY2F0aW9ucmVzdWx0cyRmcmVxdWVuY3kpLF0NCmhlYWQoc29ydGVkKQ0KDQpzdW0gPC0gc3VtKGxvY2F0aW9ucmVzdWx0cyRmcmVxdWVuY3kpDQpwZXJjZW50IDwtIHN1bS9yb3djb3VudCAqIDEwMA0KDQpwcmludCggICBzcHJpbnRmKCJUaGUgdG90YWwgZnJlcXVlbmN5IG9mIHRoZSBmbG9vci8gZmxvb3JpbmcgbWF0ZXJpYWxzIGluanVyaWVzIGlzICVpLCBvciAlLjJmJSUuIiwgc3VtLCBwZXJjZW50ICkpDQoNCmBgYA0KQXMgd2UgY29tYmluZSB0aGUgdmFyaW91cyBkYXRhIGNvbHVtbnMgdG8gb3VyIGRhdGEgZXhwbG9yYXRpb24sIHdlIGFyZSBzZWVpbmcgZGlzdGluY3QgZ3JvdXBpbmdzIG9mIHRoZSBmYWN0b3JzIHRoYXQgbWFrZSB1cCB0aGlzIGRhdGFzZXQuDQoNCg0KIyMgVGllaW5nIFRvZ2V0aGVyIHRoZSBEYXRhIEV4cGxvcmF0aW9uLg0KQXMgcHJldmlvdXNseSBvYnNlcnZlZCwgZmVtYWxlcyBhdCBob21lLCBzdWZmZXIgaW50ZXJuYWwgaW5qdXJpZXMgdG8gdGhlaXIgaGVhZHMgd2hlbiBsYW5kaW5nIG9uIHRoZSBmbG9vcnMuIExldCdzIGxvb2sgYXQgdGhlIHJldmlzZWQgZGF0YXNldCB3aGVuIHdlIGxvb2sgYXQgdGhlIG1vc3QgZnJlcXVlbnRseSBzdXN0YWluIGluanVyaWVzLg0KDQpgYGB7cn0NCmlmIChzeXN0ZW0uZmlsZShwYWNrYWdlID0gImNpcmNsZXBhY2tldFIiKSA9PSAiIikgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJjaXJjbGVwYWNrZXRSIikNCn0NCg0KbGlicmFyeShzcWxkZikNCg0KIw0KbG9jYXRpb25yZXN1bHRzIDwtIHNxbGRmKCdzZWxlY3Qgc2V4LCBsb2NhdGlvbiwgZGlhZ25vc2lzLCBib2R5X3BhcnQsIGZyZXF1ZW5jeQ0KICAgICAgICAgICAgICAgICAgICAgICAgZnJvbSgNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBTRUxFQ1Qgc2V4LCBsb2NhdGlvbiwgZGlhZ25vc2lzLCBib2R5X3BhcnQsIGNvdW50KCopIEFTICJmcmVxdWVuY3kiDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSBkZl9tYXBwZWQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAoZGlhZ25vc2lzID0gIjUzIC0gQ09OVFVTSU9OUywgQUJSLiIgb3IgZGlhZ25vc2lzID0gIjU3IC0gRlJBQ1RVUkUiIG9yIGRpYWdub3NpcyA9ICI1OSAtIExBQ0VSQVRJT04iIG9yIGRpYWdub3NpcyA9ICI2MiAtIElOVEVSTkFMIElOSlVSWSIpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgR1JPVVAgQlkgc2V4LCBsb2NhdGlvbiwgZGlhZ25vc2lzLCBib2R5X3BhcnQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBPUkRFUiBCWSBzZXgsIGxvY2F0aW9uLCBkaWFnbm9zaXMsIGJvZHlfcGFydA0KICAgICAgICAgICAgICAgICAgICAgICAgKSBhcyB0DQogICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSBmcmVxdWVuY3kgPiA1MDANCiAgICAgICAgICAgICAgICAgICAgICAgIE9SREVSIEJZIGZyZXF1ZW5jeSBERVNDDQogICAgICAgICAgICAgICAgICAgICAgICAnKQ0KDQoNCg0KDQpgYGANCg0KDQoNCiMjIEJvZHkgUGFydCAyLCBQcm9kdWN0cyAyLCBhbmQgUHJvZHVjdCAzDQpJJ20gcmVsdWN0YW50IHRvIGRlbHZlIHRvbyBkZWVwbHkgaW50byB0aGVzZSBjb2x1bW5zLiBGaXJzdCwgdGhlc2UgMyBjb2x1bW5zIGFyZSBtb3N0bHkgYmxhbmssIHNvIHdoZXJlIHRoZXJlIGlzIGRhdGEgaW4gdGhlc2UgY29sdW1ucywgaXQgc2VlbXMgdG8gYmUgYSBzZWNvbmRhcnkgcmVzdWx0IG9mIHRoZSBib2R5X3BhcnQgYW5kIHByb2R1Y3RfMS4gSW4gb3RoZXIgd29yZHMsIGlmIHdlIGNvbWUgdXAgd2l0aCBhIHdheSB0byBwcmV2ZW50IGluanVyeSB0byBib2R5X3BhcnQgd2l0aCBwcm9kdWN0XzEsIHRoZW4gd2UgY2FuIHByZXZlbnQgcHJvYmxlbXMgd2l0aCBib2R5X3BhcnRfMiBhbmQgcHJvZHVjdF8yIGFuZCBwcm9kdWN0XzMuDQoNCg0KIyBBZGRpdGlvbiBGZWF0dXJlIEVuZ2luZWVyaW5nDQoNCmBgYHtyfQ0KbGlicmFyeSh3YWZmbGUpDQoNCnJlc3VsdHMgPC0gc3FsZGYoJ1NFTEVDVCBhZ2UsIHNleCwgY291bnQoc2V4KSBBUyAiZnJlcXVlbmN5Ig0KICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSBkZl9tYXBwZWQNCiAgICAgICAgICAgICAgICAgICAgICAgIEdST1VQIEJZIGFnZSwgc2V4JykNCg0KZ2dwbG90KGRhdGE1KSArIA0KZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHg9ZGlhZ25vc2lzLCB5PWZyZXF1ZW5jeSwgY29sb3I9cmFjZSwgYWxwaGE9cmFjZSwgc2hhcGU9c2V4KSkgKyANCiAgICBsYWJzKHRpdGxlID0gIkZyZXF1ZW5jeSBvZiBJbmp1cnkgQnkgRGlhZ25vc2lzLCBHZW5kZXIsICYgcmFjZSA8MTAwIiwgeD0iRGlhZ25vc2lzIiwgeT0iQ291bnQiKQ0KYGBgDQoNCiMgRGF0YSBNb2RlbGluZyB3aXRoIEhpZWFyY2hpY2FsIE1vZGVsDQoNCmBgYHtyfQ0KDQpgYGANCg0KIyBVc2luZyBDaGF0R1BUIGZvciBBbmFseXNpcyBvZiB0aGUgTmFycmF0aXZlIERhdGENCg0KYGBge3J9DQoNCmBgYA0KDQo=